package engine;

import compressionSerialisation.GzipDialogue;
import compressionSerialisation.TfIdfIndex;
import java.io.BufferedWriter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
import javax.swing.SwingWorker;
import ui.UserInterface;

public class IndexTfIdfMaker extends SwingWorker<Void, Integer> {

    public static enum IndexType {

        Tokens, Stem
    }
    private UserInterface guiToUpdate;
    private String indexPath, indexOutPut;
    private IndexMaker.IndexType indexType;
    private TreeMap<String, ArrayList<Double>> weights;

    /**
     * @param indexPath Chemin de l'index d'entrée
     * @param indexOutPut Chemin de l'index tfIdf en sortie
     */
    public IndexTfIdfMaker(String indexPath, String indexOutPut, IndexMaker.IndexType indexType) {
        this.indexPath = indexPath;
        this.indexOutPut = indexOutPut;
        this.indexType = indexType;
    }

    //Parse une ligne de l'index normal
    private HashMap<String, Integer> parseDocumentList(String docList) {
        HashMap<String, Integer> tfDocs = new HashMap<String, Integer>();

        //DX;y
        String[] docIdTfPair = docList.split(",");

        String[] currentPair = new String[2];
        for (int i = 0; i < docIdTfPair.length; i++) {
            //Split sur ;
            currentPair = docIdTfPair[i].split(";");

            tfDocs.put(currentPair[0], Integer.parseInt(currentPair[1]));
        }

        return tfDocs;
    }

    @Override
    protected Void doInBackground() throws Exception {
        this.weights = new TreeMap<String, ArrayList<Double>>();

        String currentLine;

        Path path = Paths.get(indexPath);
        try (Scanner scanner = new Scanner(path)) {
            int lineNumber = 0;
            int nbDocs = 0;
            int nbTokens = 0;
            int currentWeightIndex = 0;
            //String currentKey;
            String currentDocList;
            double currentTfIdf;
            HashMap<String, Integer> docsTfList;
            String docId = "";

            String[] splitedLine = new String[2];//lettre : liste de docs
            
            publish(1);//1%
            while (scanner.hasNextLine()) {
                
                //System.out.println(lineNumber);
                lineNumber++;
                //System.out.println("L = " + lineNumber);
                currentLine = scanner.nextLine();

                if (lineNumber == 1) {
                    nbDocs = Integer.parseInt(currentLine.substring(currentLine.indexOf(":") + 1));
                    //System.out.println("nb nbDocs = " + nbDocs);
                } else if (lineNumber == 2) {
                    nbTokens = Integer.parseInt(currentLine.substring(currentLine.indexOf(":") + 1));
                    //System.out.println("nb nbTokens = " + nbTokens);
                }

                if (lineNumber <= 28) {
                }//Sauter les 28 premières lignes
                else {

                    //Une ligne de l'index
                    splitedLine = currentLine.split(":");
                    currentDocList = splitedLine[1];
                    docsTfList = parseDocumentList(currentDocList);
                    
                    //Pour chaque document de la clé courrante, maj le vecteur
                    for (Map.Entry<String, Integer> entry : docsTfList.entrySet()) {
                        //Maj de l'index currentWeightIndex du vecteur
                        currentTfIdf = (double) entry.getValue() * Math.log10((double) nbDocs / docsTfList.size());
                        
                        docId = entry.getKey();
                        
                        //Init l'arraylist
                        if (!weights.containsKey(docId)) {
                            weights.put(docId, new ArrayList<Double>(Collections.nCopies(nbTokens, 0.)));
                        }
                        
                        weights.get(docId).set(currentWeightIndex, currentTfIdf);
                        
                    }
                    
                    /*double sumWeights = 0;
                    for (Double d : weights.get(docId)) {
                        sumWeights += d;
                    }
                    
                    //Normaliser les poids
                    for (int i=0; i<weights.get(docId).size(); i++) {
                        weights.get(docId).set(i, weights.get(docId).get(i)/sumWeights);
                    }*/

                    currentWeightIndex++;
                    int progress = (lineNumber - 28) * 100 / nbTokens;
                    publish(progress);

                    //System.out.println("p = " + progress);
                }
            }
        }
        publish(99);//99%
        //Afficher le resultat
        //MapTools.printMapWeights(weights);
        
//        TfIdfIndex index = new TfIdfIndex(weights);
//        GzipDialogue.saveGZipObject(index, "indexTfIdfSerialized");
        
        //Ecriture dans le fichier
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(indexOutPut), Charset.defaultCharset())) {
            for (Map.Entry<String, ArrayList<Double>> entry : weights.entrySet()) {
                writer.write(entry.getKey() + ":");

                for (Double d : entry.getValue()) {
                    writer.write(d + ";");
                }
                writer.newLine();
            }
        }
        publish(100);//100%
        return null;
    }

    public void setGuiToUpdate(UserInterface guiToUpdate) {
        this.guiToUpdate = guiToUpdate;
    }

    @Override
    protected void process(List<Integer> values) {
        for (Integer val : values) {
            if (this.indexType == IndexMaker.IndexType.Tokens) {
                guiToUpdate.updateBarIndexTfIdfTokens(val);
            } else if (this.indexType == IndexMaker.IndexType.Stem) {
                guiToUpdate.updateBarIndexTfIdfStem(val);
            }
        }
    }

    @Override
    protected void done() {
        //guiToUpdate.indexTfIdfDone();
    }
}
